/* 
 * Autores:
 *      Jonathan Lopez  11106
 *      Jorge Martínez  11237
 * 
 * Archivo: Naviera.java
 * Última Revision: $Rev: 69 $
 *      Fecha: $Date: 2011-09-19 06:58:38 +0000 (Mon, 19 Sep 2011) $
 */ 

package Manejo.Transporte;

import Archivador.*;
import Manejo.Transporte.Registros.*;

import java.util.ArrayList;
import java.util.Arrays;

/**
 * Representa una empresa Naviera que posee Barcos.
 * 
 * @author Jonathan López
 * @author Jorge Martinez
 */
public class Naviera implements iArchivable{
    private RegBarcos registroBarcos;
    private RegNavieras registroNavieras;
    private final Registros registros;
    
    private ArrayList<ID> barcos;
    private String pais;

    /**
     * Constructor, inicializa todos los atributos de la clase
     * @param registroBarcos registro que contendra los barcos a usar por la naviera
     * @param registroNavieras la naviera debe de estar registrada con el registro
     * @param pais pais de la naviera
     */
    public Naviera( String pais, Registros registros )
    {
        this.registros = registros;
        this.registroBarcos = registros.obtenerRegistroBarcos();
        this.registroNavieras = registros.obtenerRegistroNavieras();
        this.pais = pais;
        
        barcos = new ArrayList<ID>();
    }

    /**
     * Retorna el pais de origen de la Naviera
     * @return pais de origen
     */
    public String obtenerPais()
    {
        return pais;
    }
    
    /**
     * Registra un Barco existente con la Naviera. Tanto el Barco como la
     * Naviera han de estar agregados en sus respectivos registros para que
     * esta función logre su cometido. NOTA: Esta función elimina el Barco
     * de la Naviera anterior con la que estuviese registrado.
     * @param idBarco ID del barco a agregar
     * @return true si la operación fue exitosa, false en caso contrario
     */
    public boolean agregarBarco( ID idBarco ){
        // Validar barco
        if( barcos.contains(idBarco) )
            return true;
        
        Barco barcoActual = registroBarcos.obtenerBarco(idBarco);
        if( barcoActual == null )
            return false;
        
        // Obtener ID de la naviera
        ID idNaviera = registroNavieras.obtenerID(this);
        if( idNaviera.equals(ID.idNulo) )
            return false;
        
        // Eliminar el Barco de la Naviera anterior
        ID idNavieraAnterior = barcoActual.obtenerNaviera();
        if( !idNavieraAnterior.equals(ID.idNulo) ){
            Naviera navieraAnterior = registroNavieras.obtenerNaviera(idNavieraAnterior);
            if( navieraAnterior != null ) navieraAnterior.eliminarBarco(idBarco);
        }
            
        
        // Agregar el barco
        barcoActual.cambiarNaviera( idNaviera );
        barcos.add(idBarco);
        
        return true;
    }
    
    /**
     * Registra un Barco existente con la Naviera. Tanto el Barco como la
     * Naviera han de estar agregados en sus respectivos registros para que
     * esta función logre su cometido. NOTA: Esta función elimina el Barco
     * de la Naviera anterior con la que estuviese registrado.
     * @param barco Referencia del Barco a agregar
     * @return true si la operación fue exitosa, false en caso contrario
     */
    public boolean agregarBarco( Barco barco ){
        ID idBarco = registroBarcos.obtenerID(barco);
        return agregarBarco( idBarco );
    }
    
    /**
     * Elimina un Barco de la Naviera con la cual está asignada.
     * @param idBarco ID del Barco a eliminar
     * @return true si la operación fue exitosa, false en caso contrario
     */
    public boolean eliminarBarco( ID idBarco ){
        // Elimina un Barco del registro de la Naviera
        if( barcos.contains( idBarco ) )
            barcos.remove( idBarco );
        else
            return false;
        
        // Elimina el registro con la Naviera
        Barco barco = registroBarcos.obtenerBarco(idBarco);
        if( barco != null )
            barco.cambiarNaviera( ID.idNulo );
        else
            return false;
        
        return true;
    }
    
    /**
     * Regresa el primer Barco libre que no tiene un viaje asignado y que esté
     * registrado a esta Naviera. Regresa null si el no hay Barco disponible.
     * @return primer Barco libre
     */
    public Barco obtenerBarcoLibre(){
        // Un barco esta libre si no tiene Viaje asignado
        for( ID idBarco: barcos ){
            // Obtener objeto
            Barco barcoActual = registroBarcos.obtenerBarco(idBarco);
            
            if( barcoActual.obtenerViaje() == null )
                return barcoActual;
        }
        
        return null;
    }
    
    /**
     * Regresa los ID's de todos los barcos registrados con esta Naviera
     * @return arreglo con los ID's de todos los barcos registrados
     */
    public ID[] obtenerBarcos(){
        return barcos.toArray( new ID[0] );
    }

    /**
     * Regresa una representación String de la Naviera
     * @return String
     */
    @Override
    public String toString()
    {
        // Obtener los nombres de los Barcos
        String[] nombreBarcos = new String[barcos.size()];
        for (int n = 0; n < barcos.size(); n++) {
            ID idBarco = barcos.get(n);
            nombreBarcos[n] = registroBarcos.obtenerNombre(idBarco);
        }
        String sBarcos = "";
        if( nombreBarcos.length != 0 )
            sBarcos = ", barcos=" + Arrays.toString(nombreBarcos);
        
        return "Naviera{" + pais + sBarcos + '}';
    }
    
/**
     * Regresa un línea de texto para ser guardada en un medio persistente.
     * @return String
     * @see iArchivable#guardar() 
     */

    @Override
    public String guardar()
    {
        // Orden: pais, barcos
        String linea = "[";
        linea += pais + separador;
        
        for( ID idBarco: barcos )
            linea += idBarco.guardar() + separador;
        
        linea += "]";
        return linea;
    }
    
    /**
     * Genera una nueva Naviera a partir de una línea de texto creada a través
     * del método guardar()
     * @param linea
     * @param registroBarcos
     * @param registroNavieras
     * @return nueva Naviera generada por el String, o null si falla
     */
    public static Naviera parseNaviera( String linea, Registros registros ){
        // Validar linea
        if( !Util.validarLinea(linea) )
            return null;
        
        String srNaviera = Util.eliminarExtremos(linea);
        if( srNaviera.equals("") )
            return null;
        
        // Partir objetos
        String[] partes = srNaviera.split(separador);
        int minimoPartes = 1;
        if( partes.length < minimoPartes )
            return null;
        
        // Orden: pais, barcos
        String _pais = "";
        ArrayList<ID> _barcos = new ArrayList<ID>();
        for (int n = 0; n != partes.length; n++) {
            if( n == 0 )
                _pais = partes[n];
            else{
                ID idBarco = ID.parseID( partes[n] );
                if( idBarco.equals(ID.idNulo))
                    // DEBUG
                    System.out.println("**ID MALO**");
                else
                    _barcos.add(idBarco);
            }
        }
        
        // Crear Naviera
        Naviera nuevaNaviera = new Naviera( _pais, registros );
        nuevaNaviera.barcos = _barcos;
        
        return nuevaNaviera;
    }
    
    /**
     * Punto de entrada para las pruebas unitarias de Naviera
     * @param args 
     */
    public static void main( String[] args ){
        int pruebas = 10;
        int fallos = 0;
        java.util.Random gen = new java.util.Random();
        Registros registros = new Registros();
        
        RegBarcos registroBarcos = registros.obtenerRegistroBarcos();
        RegNavieras registroNavieras = registros.obtenerRegistroNavieras();
        
        // Generar nuevos barcos
        int totalBarcos = 10;
        ID[] barcos = new ID[totalBarcos];
        for (int i = 0; i != totalBarcos; i++){
            Barco nuevoBarco = new Barco( gen.nextDouble(), null, registros );
            barcos[i] = registroBarcos.agregarBarco(nuevoBarco, 
                    Integer.toHexString(gen.nextInt()) );
        }
            
        
        // Generar navieras
        for (int n = 0; n != pruebas; n++) {
            Naviera naviera = new Naviera( "GUATEMALA CA", registros );
            registroNavieras.agregarNaviera(naviera, Integer.toHexString(gen.nextInt()));
            int agregarBarcos = gen.nextInt( 10 );
            for (int i = 0; i != agregarBarcos; i++)
                naviera.agregarBarco( barcos[gen.nextInt(totalBarcos)]);
            
            String linea = naviera.guardar();
            Naviera nuevaNaviera = Naviera.parseNaviera(linea, registros);
            
            boolean iguales = naviera.toString().equals(nuevaNaviera.toString());
            if( !iguales )
                ++fallos;
            
            System.out.println(linea + " & " + iguales);
            System.out.println("\t" + naviera);
            System.out.println("\t" + nuevaNaviera);
        }
        
        System.out.println("FALLOS: " + fallos);
        
        registroNavieras.guardarTodo();
        Informador.guardarCambios();
        /*
        System.out.println("\n--NAVIERAS--");
        for( Naviera n: registroNavieras.obtenerTodasNavieras() )
            System.out.println(n);
         */
    }
    
}
